#include "StdAfx.h"
//@author U094709Y
#include "UserInterface.h"

const string UserInterface::MESSAGE[NUMBER_OF_SYSTEM_MSG] = {
				"'%s' is added to Tasker", 
                "Tasks for %s are cleared",
				"All tasks are cleared",
                "'%s' is deleted from Tasker", 
                "'%s' is marked as done",
                "There are no tasks in Tasker", 
                "invalid command : %s", 
                "%s is an invalid date",
                "%s is an invalid integer",
                "'%s' is an invalid task name",
                "Task %s is not listed",
                "%s is %s time",
                "No results are found for %s",
				"Task %s's %s is modified with '%s'",
				"Invalid edit command: '%s'. Select a valid task category to edit",
				"There is no %s task",
				"There is no task on %s to be %s",
				"Timing is not specified for '%s'",
				"'%s' has already been marked as done",
				"'%s' is marked as uncompleted",
				"No operations were performed before this to be undone",
				"%s is before the deadline of the task. Select date after task's current deadline to perform postpone", 
				"'%s' does not have a date to be repeated on",
				"There are no further %s for the task to be repeated in the %s of %s", 
				"Invalid frequency to be repeated on : %s",
				"'%s' has been postponed to %s", 
				"All tasks on %s have been postponed to %s"
        };

const std::string UserInterface::MESSAGE_WELCOME = "Welcome to Tasker.\nFor more information on the list of commands available, type \"help\"\nPlease enter your command below.";

char UserInterface::systemMessage[BUFFER_SIZE];
bool UserInterface::isPrintSystemMessage = false;	

#pragma region Translating User Input

string UserInterface::readUserInput(System::String^ input, UserInterface::DISPLAY_TYPE uiType, bool isDone)      //for when multiple controls on form
{
        string command;
		if(stringObjToStdConversion(input, command))
		{
			switch(uiType)
			{
			case CHECKEDBOXLIST:
				if(isDone)
					command = "done " + command;
				else
					command = "undone " + command;
				break;
			case SELECTLIST_PENDING:
			case SELECTLIST_FLOATING:
				command = "show detail " + command;
				break;
			default:
				break;
			}
            return trim(command);
		}
        else
            return "";
}

string UserInterface::sendingInputToExecutor(string& input)
{
        Executor execute;
        return execute.executeCommand(input);
}

#pragma endregion

#pragma region Display Messages

string UserInterface::generateWelcomeMessage(void)
{
        return MESSAGE_WELCOME;
}

void UserInterface::clearSystemMessage(void)
{
	sprintf_s(systemMessage, "", "");
}

string UserInterface::generateMessage(string msg, string param, string param1, string param2)
{
	if(msg.empty())
	{
		clearSystemMessage();
		return "";
	}
	else
	{
        MESSAGE_TYPE message_t = determineMessageType(msg);
        sprintf_s(systemMessage, MESSAGE[message_t].c_str(), param.c_str(), param1.c_str(), param2.c_str());
		isPrintSystemMessage = true;
        return systemMessage;
	}
}

UserInterface::MESSAGE_TYPE UserInterface::determineMessageType(string msg)
{
        if(msg == "added") {
            return MESSAGE_TYPE::ADDED;
        } else if (msg == "deleted") {
            return MESSAGE_TYPE::DELETED;
        } else if (msg == "invalidTaskNum") {
            return MESSAGE_TYPE::INVALID_TASK_NO;
        } else if (msg == "notInt") {
            return MESSAGE_TYPE::INVALID_INT;
        } else if (msg == "isEmptyFile") {
            return MESSAGE_TYPE::EMPTY_FILE;
        } else if (msg == "invalidDate") {
            return MESSAGE_TYPE::INVALID_DATE;
        } else if (msg == "matchUnfound") {
            return MESSAGE_TYPE::MATCH_UNFOUND;
        } else if (msg == "cleared") {
            return MESSAGE_TYPE::CLEARED;
        } else if (msg == "Done") {
            return MESSAGE_TYPE::DONE;
        } else if (msg == "invalidTime") {
            return MESSAGE_TYPE::INVALID_TIME;
        } else if (msg == "invalidName") {
            return MESSAGE_TYPE::INVALID_TASK;
		} else if (msg == "clearAll") {
			return MESSAGE_TYPE::CLEARED_ALL;
		} else if (msg == "editted") {
			return MESSAGE_TYPE::EDITTED;
		} else if (msg == "invalidEdit") {
			return MESSAGE_TYPE::INVALID_EDIT_CMD;
		} else if (msg == "noTaskOfType") {
			return MESSAGE_TYPE::NO_TASK_OF_TYPE;
		} else if (msg == "noTimingTask") {
			return MESSAGE_TYPE::NO_TIMING;
		} else if (msg == "alreadyMarkedDone") {
			return MESSAGE_TYPE::ALREADY_DONE;
		} else if (msg == "noTaskOnCmdDate") {
			return MESSAGE_TYPE::NO_TASK_ON;
		} else if (msg == "invalidPostpone") {
			return MESSAGE_TYPE::INVALID_POSTPONE;
		} else if (msg == "Undone") {
			return MESSAGE_TYPE::UNDONE;
		} else if (msg == "invalidUndo") {
			return MESSAGE_TYPE::INVALID_UNDO;
		} else if (msg == "undatedTaskToRepeat") {
			return MESSAGE_TYPE::UNDATED_REPEAT;
		} else if (msg == "noDateToRepeat") {
			return MESSAGE_TYPE::NODATE_REPEAT;
		} else if (msg == "invalidFreqToRepeat") {
			return MESSAGE_TYPE::INVALID_FREQ;
		} else if (msg == "postponedSingle") {
			return MESSAGE_TYPE::POSTPONED_SINGLE;
		} else if (msg == "postponedAll") {
			return MESSAGE_TYPE::POSTPONED_ALL;
        } else {
			return MESSAGE_TYPE::INVALID_CMD;
        } 
}

string UserInterface::getSystemMessage(void)
{
	string messageToBePrinted;
	if(isPrintSystemMessage)
		messageToBePrinted = systemMessage;
	else
		messageToBePrinted = "";
	clearSystemMessage();
	isPrintSystemMessage = false;
	return messageToBePrinted;
}

#pragma endregion

string UserInterface::generateHelpList(void)
{
		string cmdHelp = "LEGEND (the brackets are to be omitted from actual command):\n{} = OPTIONAL.\n[] = FORMAT/TYPE OF USER INPUT.\n() = CHOOSE ONE OF THE CHOICES\n\n";
		cmdHelp += "TO ADD A TASK:\n add [task name] {-date [dd/mm/yyyy] -starts [hhmm] -ends [hhmm] -detail [detail] -impt -repeat [weekly/monthly]}\n\n";
        cmdHelp += "TO DELETE A TASK FROM LIST:\n delete [task number]\n\n";

        cmdHelp += "TO VIEW TASKS:\n";
		cmdHelp += "All tasks: show \n";
        cmdHelp += "Tasks by category: show (impt/done/undone)\n";
        cmdHelp += "Tasks on a particular day: show [dd/mm/yyyy]\n";
		cmdHelp += "Floating tasks: show floating\n\n";
		cmdHelp += "TO VIEW DETAILS/TIME OF A TASK:\n show (detail/time) [task number]\n\n"; 

        cmdHelp += "TO FIND A TASK:\n search [task name/ part of task name]\n\n";

        cmdHelp += "TO CLEAR TASKS:\n";
		cmdHelp += "All tasks in system: clear\n";
		cmdHelp += "All tasks on a particular day: clear [dd/mm/yyyy]\n\n";

        cmdHelp += "TO MARK A TASK AS COMPLETED:\n done [task number]\n";
		cmdHelp += "TO MARK A TASK AS UNCOMPLETED:\n undone [task number]\n\n";

		cmdHelp += "TO EDIT A TASK WITHIN LIST:\n edit [task number]\n";
		cmdHelp += "Select one of the following categories to append to the command to edit that particular element:\n";
		cmdHelp += " -date [dd/mm/yyyy]\n -starts [hhmm]\n -ends [hhmm]\n (-impt/-unimpt)\n -detail [detail]\n -repeat [weekly/monthly]";

		cmdHelp += "TO POSTPONE TASKS:\n";
		cmdHelp += "All tasks to a particular day: postpone all [current date of tasks] [date to be postponed to]\n";
		cmdHelp += "A particular task to a particular day: postpone [tasknumber] [date]\n\n";

		cmdHelp += "TO UNDO:\n undo\n\n";

		cmdHelp += "TO EXIT THE SYSTEM:\n exit";

        return cmdHelp;
}

#pragma region System Initialization

void UserInterface::startingExecutor(void)
{
        Executor execute;
        execute.loadVect();
}

#pragma region checkBoxList

DataTable^ UserInterface::getTaskList(string date)
{
	DataTable^ taskList;
	Executor execute;
	vector<int> fileIndex;
	vector<string> subject;
	vector<bool> done;

	//For Testing
	//int fileIndex[] = {10, 20, 30, 40};
	//string subject[] = {"happy", "birthday", "to", "you"};
	//bool done[] = {true, false, false, true};
	//int listSize = 4;
	
	taskList = generateTableType(CHECKEDBOXLIST);
	if(execute.isRetrievedTaskList(date, fileIndex, subject, done))
	{
		int listSize = subject.size();
		for(int i = 0; i < listSize; i++)
		{
			DataRow^ oneTask = taskList->NewRow();
			oneTask->default["index"] = fileIndex[i];
			oneTask->default["subject"] = gcnew System::String(subject[i].c_str());
			oneTask->default["done"] = gcnew System::Boolean(done[i]);
			taskList->Rows->Add(oneTask);
		}
	}
	else
	{
		//Fill datatable with a task named no task loaded
		DataRow^ oneTask = taskList->NewRow();
		oneTask->default["index"] = -1;
		oneTask->default["subject"] = "No task for " + gcnew System::String(date.c_str());
		oneTask->default["done"] = false;
		taskList->Rows->Add(oneTask);
	}

	return taskList;
}

#pragma endregion

#pragma region pendingList

DataTable^ UserInterface::getPendingList(void)
{
	DataTable^ taskList;
	Executor execute;
	vector<int> fileIndex;
	vector<string> subject;

	//For Testing
	//int fileIndex[] = {10, 20, 30, 40};
	//string subject[] = {"happy", "birthday", "to", "you"};
	//int listSize = 4;
	

	taskList = generateTableType(SELECTLIST_PENDING);
	if(execute.isRetrievedPendingTasks(fileIndex, subject))
	{
		int listSize = subject.size();
		for(int i = 0; i < listSize; i++)
		{
			DataRow^ oneTask = taskList->NewRow();
			oneTask->default["index"] = fileIndex[i];
			oneTask->default["subject"] = gcnew System::String(subject[i].c_str());
			taskList->Rows->Add(oneTask);
		}
	}
	else
	{
		//throw "No Task";
		//Fill datatable with a task named no task loaded
		DataRow^ oneTask = taskList->NewRow();
		oneTask->default["index"] = -1;
		oneTask->default["subject"] = "No pending task";
		taskList->Rows->Add(oneTask);
	}

	return taskList;
}
#pragma endregion

#pragma region floatingList

DataTable^ UserInterface::getFloatingList(void)
{
	DataTable^ taskList;
	Executor execute;
	vector<int> fileIndex;
	vector<string> subject;

	//For Testing
	//int fileIndex[] = {10, 20, 30, 40};
	//string subject[] = {"happy", "birthday", "to", "you"};
	//int listSize = 4;
	

	taskList = generateTableType(SELECTLIST_FLOATING);
	if(execute.isRetrievedFloatingTasks(fileIndex, subject))
	{
		int listSize = subject.size();
		for(int i = 0; i < listSize; i++)
		{
			DataRow^ oneTask = taskList->NewRow();
			oneTask->default["index"] = fileIndex[i];
			oneTask->default["subject"] = gcnew System::String(subject[i].c_str());
			taskList->Rows->Add(oneTask);
		}
	}
	else
	{
		//throw "No Task";
		//Fill datatable with a task named no task loaded
		DataRow^ oneTask = taskList->NewRow();
		oneTask->default["index"] = -1;
		oneTask->default["subject"] = "No incompleted floating task";
		taskList->Rows->Add(oneTask);
	}

	return taskList;
}

#pragma endregion

#pragma endregion

DataTable^ UserInterface::generateTableType(UserInterface::DISPLAY_TYPE displayFormat)
{
	DataTable^ table = gcnew DataTable();
	DataColumn^ column;
	switch(displayFormat)
	{
	case TASK_DETAIL:
		column = gcnew DataColumn();
		column->DataType = System::Type::GetType("System.String");
		column->ColumnName = "detail";
		table->Columns->Add(column);
	case TASK_DISPLAY: 
		column = gcnew DataColumn();
		column->DataType = System::Type::GetType("System.DateTime");
		column->ColumnName = "start";
		table->Columns->Add(column);
		column = gcnew DataColumn();
		column->DataType = System::Type::GetType("System.DateTime");
		column->ColumnName = "end";
		table->Columns->Add(column);
	case CHECKEDBOXLIST:
		column = gcnew DataColumn();
		column->DataType = System::Type::GetType("System.Boolean");
		column->ColumnName = "done";
		table->Columns->Add(column);
	case SELECTLIST_PENDING:
	case SELECTLIST_FLOATING:
		column = gcnew DataColumn();
		column->DataType = System::Type::GetType("System.String");
		column->ColumnName = "subject";
		table->Columns->Add(column);
	default:
		column = gcnew DataColumn();
		column->DataType = System::Type::GetType("System.Int32");
		column->ColumnName = "index";
		table->Columns->Add(column);
	}
	array<DataColumn^>^ key = gcnew array<DataColumn^>(1);
	key[0] = table->Columns->default["index"];
	table->PrimaryKey = key;
	return table;
}


string UserInterface::getDateOrTime(System::String^ dateTime, bool isDate)
{
	string dateTimeString;
    if(stringObjToStdConversion(dateTime, dateTimeString))
	{
		int spacePos = dateTimeString.find(' ');
		bool noSpacing = (spacePos == string::npos);
		if(noSpacing)
			return trim(dateTimeString);
		else if(isDate)
            return trim(dateTimeString.substr(0, spacePos));
		else
			return trim(dateTimeString.substr(spacePos));		//should create another function that converts the time to 24h format
	}
    else
        return "";
}

bool UserInterface::stringObjToStdConversion(System::String^ source, string& result)
{
        int len = ((source->Length+1)*2);
        char* temp = new char[len];

        pin_ptr<const wchar_t> wch = PtrToStringChars( source );
        bool success = wcstombs( temp, wch, len ) != -1;

        result = temp; 
        delete temp; 
        return success;
}

inline string UserInterface::trim(const string& s, const string& delimiters) 
{
        if(!s.empty())
        {
                int tail = s.find_last_not_of(delimiters) + 1;
                int head = s.find_first_not_of(delimiters);
                if((head == string::npos) || (tail == string::npos))
                        return "";
                return s.substr(head, tail);
        }
        else
                return s;
}